#include "classsemantic.h"
#include "method.h"
#include "field.h"
#include "visitordata.h"
#include "../core/nodes/list.h"
#include "../core/nodes/creator.h"

ClassSemantic::ClassSemantic(ClassNode * cnode)
{
	m_hierarchy_visited=false;
	m_class=cnode;
	m_isroot=false;
	m_table=NULL;
}

void ClassSemantic::printAttrTable()
{
 for (std::map<std::string,Field>::iterator it=m_fields.begin();it!=m_fields.end();it++)
 {
	 printf("%s %s%s;\n",it->second.m_type->fullName().c_str(),it->second.m_classname.c_str(),it->second.m_realname.c_str());
 }
 for (std::map<std::string,Method>::iterator it=m_methods.begin();it!=m_methods.end();it++)
 {
	 Method * meth=&(it->second);
	 const Method * ovnonabs=meth->getOverridenNonAbstractMethod();
	 if (ovnonabs)
	 {
		printf("%s%s { %p }\n",ovnonabs->m_classname.c_str(),ovnonabs->m_realname.c_str(),meth->m_routine);
		printf("%s%s { %s%s }\n",meth->m_classname.c_str(),meth->m_realname.c_str(),
								ovnonabs->m_classname.c_str(),ovnonabs->m_realname.c_str());
		for (unsigned int i=0;i<meth->m_overriden_methods.size();i++)
		 {
			 Method * overriden=&(meth->m_overriden_methods[i]);
			 if (overriden!=ovnonabs)
			 {
			  printf("%s%s { %s%s }\n",overriden->m_classname.c_str(),overriden->m_realname.c_str(),
								     ovnonabs->m_classname.c_str(),ovnonabs->m_realname.c_str());
			 }
		 }
	 }
	 else
	 {
		 printf("%s%s { %p }\n",meth->m_classname.c_str(),meth->m_realname.c_str(),meth->m_routine);
		 for (unsigned int i=0;i<meth->m_overriden_methods.size();i++)
		 {
			 Method * overriden=&(meth->m_overriden_methods[i]);
			 printf("%s%s { %s%s }\n",overriden->m_classname.c_str(),overriden->m_realname.c_str(),
								      meth->m_classname.c_str(),meth->m_realname.c_str());
		 }
	 }
	 
 }
  /*
  printf("Methods:\n");
  for (std::map<std::string,Method>::iterator it=m_methods.begin();
	   it!=m_methods.end();
	   it++)
  {
	  printf("Method: %s",it->first.c_str());

	  printf(" from %s",it->second.m_classname.c_str());
	  int type=it->second.m_type;
	  if (type & FDT_ABSTRACT)
		  printf(" abstract");
	  if (type & FDT_FROZEN)
		  printf(" frozen");
	  if (type & FDT_LIBRARY)
		  printf(" predefined");
	  printf("\n");
  }
  printf("Fields:\n");
  for (std::map<std::string,Field>::iterator it=m_fields.begin();
	   it!=m_fields.end();
	   it++)
  {
	  printf("Field: %s",it->first.c_str());
	  printf(" from %s",it->second.m_classname.c_str());
	  int type=it->second.m_decltype;
	  if (type & FDT_ABSTRACT)
		  printf(" abstract");
	  if (type & FDT_FROZEN)
		  printf(" frozen");
	  if (type & FDT_LIBRARY)
		  printf(" predefined");
	  printf("\n");
  }
  printf("Operators:\n");
  for (unsigned int i=0;i<m_operators.size();i++)
  {
	  printf("Operator: %s from %s ",m_operators[i].m_operatorname.c_str(),
		                             m_operators[i].m_ownerclassname.c_str());
	  printf(" implemented as %s",m_operators[i].m_methodname.c_str());
	  printf("\n");
  }
  printf("\n\n\n");
  */
}

void ClassSemantic::addInheritance(const std::string & ancestor, const  InheritanceSemantic & sem)
{
	m_inheritance.insert(std::make_pair<std::string,InheritanceSemantic>(ancestor,sem));
}


void ClassSemantic::generateFlatShotForm(SemanticVisitorData * data)
{
	//If we generated a fsf already, leave
	if (m_hierarchy_visited)
		return;
	//Mark node  as visited
	m_hierarchy_visited=true;

	for (std::map<std::string,InheritanceSemantic>::iterator it=m_inheritance.begin();
		it!=m_inheritance.end();
		it++)
	{
	 ClassSemantic * ptr=NULL;
	 if (data->getClassByName(it->first,ptr))
	 {
		 FlatShortForm fsf=ptr->getFlatShotForm(data);
		 merge(data,it->first,it->second,fsf);
	 }
	}
}

class MergeData
{
 public:
         SemanticVisitorData * data;
		 std::string inheritedClassName;
		 InheritanceSemantic * redefren;
		 
		 std::string oldName;
		 Field   *    field;


		 Method  *    method;
		 Operator *   op;
		 
		 inline MergeData() {}

};

void ClassSemantic::merge(SemanticVisitorData * data, 
						   const std::string & inheritedClassName,
			               InheritanceSemantic & redefren,
			               FlatShortForm  & fsf
		                  )
 {
  MergeData * mg=new MergeData();
  mg->data=data;
  mg->inheritedClassName=inheritedClassName;
  mg->redefren=&redefren;
  
  for (std::map<std::string, Field>::iterator it=fsf.m_fields->begin();
	   it!=fsf.m_fields->end();
	   it++)
  {
	  mg->oldName=it->first;
	  mg->field=&(it->second);
	  mergeField(mg);
  }

  for (std::map<std::string,Method>::iterator it=fsf.m_methods->begin();
	   it!=fsf.m_methods->end();
	   it++)
  {
	  mg->oldName=it->first;
	  mg->method=&(it->second);
	  mergeMethod(mg);
  }

  for (unsigned int i=0;i<fsf.m_operators->size();i++)
  {
	  mg->oldName=(*(fsf.m_operators))[i].m_methodname;
	  mg->method=&((*(fsf.m_methods))[mg->oldName]);
	  mg->op=&((*(fsf.m_operators))[i]);
	  mergeOperator(mg);
  }
  delete mg;
 }

void ClassSemantic::mergeField(MergeData * data)
{
	//std::string ckname;
	Rename * rename=NULL;
	if (data->redefren->getRename(data->oldName,&rename))
	{
		if (rename->Alias.length())
			data->data->add(new OperatorField(m_class));
	}
	std::string cname=data->oldName;
    if (rename)
		cname=rename->NewName;
	if (m_fields.find(cname)!=m_fields.end())
	{
		std::string redef="field";
		data->data->add(new DataRedefinitionError(m_fields[cname].node(),NULL,redef,cname));
	}
	else
	{
		m_fields.insert(std::make_pair<std::string,Field>(cname,*(data->field)));
	}
}

bool ClassSemantic::getOperatorBySignature(const std::string & s,MethodSignature & o,  Method ** out)
{
 for (unsigned int i=0;i<m_operators.size();i++)
 {
	 if (m_operators[i].m_operatorname==s)
	 {
	  MethodSignature m(m_methods[m_operators[i].m_methodname]);
	   if (m==o)
	   {
		   *out=&(m_methods[m_operators[i].m_methodname]);
		   return true;
	   }
	 }
 }
 return false;
}

bool Method::overridesMethod(const std::string & classname, 
							 const std::string & methodname)
{
	for (unsigned int i=0;i<m_overriden_methods.size();i++)
	{
		if (m_overriden_methodnames[i]==methodname && m_overriden_methods[i].m_classname==classname)
			return true;
	}
	return false;
}

void ClassSemantic::mergeMethod(MergeData * data)
{
  Rename * rename=NULL;
  data->redefren->getRename(data->oldName,&rename);
  std::string cname=data->oldName;
  if (rename)
		cname=rename->NewName;
  
  bool error=false; 
  if (m_methods.find(cname)!=m_methods.end())
  {
	  error=true;
	  MethodSignature newsig(m_methods[cname]);
	  MethodSignature oldsig(*(data->method));
	  if (newsig==oldsig)
	  {
		  error=false;
		  if (!(data->redefren->isRedefined(cname)))
		  {
			  data->data->add(new ImplicitRedefinition(m_methods[cname].node(),cname));
		  }
		  else
		  {
			  Method * overriden=const_cast<Method*>(data->method->getOverridenNonAbstractMethod());
			  if (overriden==NULL)
				overriden=data->method;
			  m_methods[cname].overrideMethod(overriden,data->oldName);
			  m_methods[cname].mustCompile();
			  m_methods[cname].setLastOverridenFrom(data->inheritedClassName);
		  }
		  if ( (data->method->m_type & FDT_FROZEN)!=0)
		  {
			  data->data->add(new FrozenRedefinition(m_methods[cname].node(),cname));
		  }
		  int mytype=m_methods[cname].m_type;
		  int parenttype=data->method->m_type;
		  if ( (parenttype & FDT_ABSTRACT)==0
			   && (mytype & FDT_ABSTRACT)!=0)
		  {
			  data->data->add(new EffectiveToAbstractReplace(m_methods[cname].node(),cname));
		  }
	  }
	  if (error)
	  {
		std::string redef="method";
		data->data->add(new DataRedefinitionError(m_methods[cname].node(),NULL,redef,cname));
	  }
  }
  else
  {
		m_methods.insert(std::make_pair<std::string,Method>(cname,*(data->method)));
		m_methods[cname].dontCompile();
		m_methods[cname].dontCompileMainMethod();
		m_methods[cname].m_class_from_which_inherited=data->inheritedClassName;
  }

  //If renaming leads to operator creation
  if (rename)
  {
	  if (rename->Alias.length())
	  {
		  Operator op(data->method->m_clients,
			          data->method->m_classname,
			          cname,
					  rename->Alias
					 );
		  MethodSignature msig(*(data->method));
		  Method * oldmethod=NULL;
		  if (getOperatorBySignature(rename->Alias,msig,&oldmethod))
		  {
			  if (!(oldmethod->overridesMethod(data->method->m_classname,data->oldName)))
			  {
				  data->data->add(new OperatorAlreadyDefined(oldmethod->node(),
															 rename->Alias,
															 msig.formalArgList())
					             );
			  }
		  }
		  else
			  m_operators.push_back(op);
	  }
  }
}

void ClassSemantic::mergeOperator(MergeData * data)
{
	MethodSignature oldsig(*(data->method));
    Method * newmethod=NULL;
	if (getOperatorBySignature(data->op->m_operatorname,oldsig,&newmethod))
	{
		if (newmethod->overridesMethod(data->method->m_classname,data->op->m_methodname))
		{
			bool hasOp=false;
			for (unsigned int i=0;(i<m_operators.size()) && (!hasOp);i++)
			{
				if (newmethod==&(m_methods[m_operators[i].m_methodname])
					&& m_operators[i].m_operatorname==data->op->m_operatorname)
					hasOp=true;
			}
			if (!hasOp)
				m_operators.push_back(*(data->op));
		}
		else
		{
		  data->data->add(new OperatorAlreadyDefined(newmethod->node(),
													(data->op->m_operatorname),
													oldsig.formalArgList())
					     );
		}
	}
	else
	{
		Rename * rename=NULL;
		data->redefren->getRename(data->op->m_methodname,&rename);
		Operator copy(*(data->op));
		if (rename)
			copy.m_methodname=rename->NewName;
		m_operators.push_back(copy);
	}
}
FlatShortForm ClassSemantic::getFlatShotForm(SemanticVisitorData *data)
{
	generateFlatShotForm(data);
	return FlatShortForm(m_fields,m_methods,m_operators);
}


Method * ClassSemantic::getMethodByName(const std::string & name)
{
	if (m_methods.find(name)!=m_methods.end())
		return &(m_methods[name]);
	return NULL;
}

Field * ClassSemantic::getFieldByName(const std::string & name)
{
	if (m_fields.find(name)!=m_fields.end())
		return &(m_fields[name]);
	return NULL;
}

void ClassSemantic::fixClients()
{
	for (std::map<std::string,Method>::iterator it=m_methods.begin();it!=m_methods.end();it++)
		it->second.fixClients(m_class->name());
	for (std::map<std::string,Field>::iterator it=m_fields.begin();it!=m_fields.end();it++)
		it->second.fixClients(m_class->name());
}

ClassSemantic::~ClassSemantic()
{
	for (unsigned int i=0;i<m_constructors.size();i++)
	{
		delete m_constructors[i];
	}
	delete m_table;
}

Constructor * ClassSemantic::getConstructorByMethodName(const std::string & name)
{
	for (unsigned int i=0;i<m_constructors.size();i++)
	{
		if (m_constructors[i]->Method==name)
			return m_constructors[i];
	}
	return NULL;
}

void ClassSemantic::findConstructors(ParentData * parent)
{
 parent->CurrentClass=this;
 if (cnode()->creators()) 
 {
	 const std::vector<CreatorNode *> & v=cnode()->creators()->vector();
	 for (unsigned int i=0;i<v.size();i++)
	 {
		 v[i]->createConstructors(parent);
	 }
 }
}
bool ClassSemantic::addConstructor(const std::string & name, const std::vector<std::string > & clients)
{
	if (getConstructorByMethodName(name))
		return false;
	m_constructors.push_back(new Constructor(clients,name));
	return true;
}

void ClassSemantic::fillConverters(ParentData *parent)
{
	parent->CurrentClass=this;
	if (cnode()->converters())
	{
		const std::vector<ConverterNode *> & v=cnode()->converters()->vector();
		for (unsigned i=0;i<v.size();i++)
		{
		   v[i]->createConverter(parent);
		}
	}
}

void ClassSemantic::checkFormalArgsAndLocalVars(ParentData * data)
{
	data->CurrentClass=this;
	for (std::map<std::string,Method>::iterator it=m_methods.begin();it!=m_methods.end();it++)
	{
		it->second.checkFormalAndLocalVars(data);
	}
}

void ClassSemantic::applyVisitor(MethodVisitor * visitor)
{
	visitor->data()->CurrentClass=this;
	visitor->visitClass();
	visitor->preFields();
	for (std::map<std::string,Field>::iterator it=m_fields.begin();it!=m_fields.end();it++)
	{
		visitor->data()->CurrentField=&(it->second);
		bool test=it->second.m_classname==this->cnode()->name();
		if (test)
			visitor->visitField();
	}
	visitor->preMethods();
	for (std::map<std::string,Method>::iterator it=m_methods.begin();it!=m_methods.end();it++)
	{
		visitor->data()->CurrentMethod=&(it->second);
		bool test=it->second.m_classname==this->cnode()->name() || it->second.shouldCompile();
		if (test && (it->second.methodType() & FDT_LIBRARY)==0)
		{
		  visitor->visitMethod();
		}
	}
	visitor->postVisitClass();
}

void ClassSemantic::collectParents(std::vector<std::vector<std::string> > & waves, int index, SemanticVisitorData * data)
{
	if (waves.size()==index)
	{
		waves.push_back(std::vector<std::string>());
	}
	for (std::map<std::string,InheritanceSemantic>::iterator it=m_inheritance.begin();it!=m_inheritance.end();it++)
	{
		waves[index].push_back(it->first);
	}
	for (std::map<std::string,InheritanceSemantic>::iterator it=m_inheritance.begin();it!=m_inheritance.end();it++)
	{
		ClassSemantic * sem=data->getClassByName(it->first);
		if (sem)
		{
			sem->collectParents(waves,index+1,data);
		}
	}
}

void ClassSemantic::buildHierarchy(std::vector<std::string> & hierarchy, SemanticVisitorData * data)
{
	std::vector<std::vector<std::string> > waves;
	waves.push_back(std::vector<std::string>());
	waves[0].push_back(cnode()->name());
	collectParents(waves,1,data);
	for (unsigned int i=0;i<waves.size();i++)
	{
		for (unsigned int j=0;j<waves[i].size();j++)
		{
			hierarchy.push_back(waves[i][j]);
		}
	}
}


bool ClassSemantic::canConvertWithoutDowncast(const std::string & type, SemanticVisitorData * data)
{
	if (type==cnode()->name())
	{
		return true;
	}
	bool isAncestor=data->isAncestor(type,cnode()->name());
	bool canConvertsTo=convertsTo(type);
	return isAncestor || canConvertsTo;
}

Method * ClassSemantic::getArrayPutOperator(ClassSemantic * indexType,ClassSemantic * putType,SemanticVisitorData * data)
{
	for (unsigned int i=0;i<m_operators.size();i++)
	{
		if (m_operators[i].m_operatorname=="[]:=")
		{
			Method * meth=getMethodByName(m_operators[i].m_methodname);
			int startarg=0;
			if (meth->findFormalArg("CURRENT")==0)
				startarg=1;
			//If fully exposed, use it
			if ( (indexType==NULL || meth->getArgByIndex(startarg,false)->fullName()==indexType->cnode()->name())
				&& ( putType==NULL || meth->getArgByIndex(startarg+1,false)->fullName()==putType->cnode()->name()) )
				return meth;
		}
	}
	
	for (unsigned int i=0;i<m_operators.size();i++)
	{
		if (m_operators[i].m_operatorname=="[]:=")
		{
			Method * meth=getMethodByName(m_operators[i].m_methodname);
			int startarg=0;
			if (meth->findFormalArg("CURRENT")==0)
				startarg=1;
			//If fully exposed, use it
			if (indexType->canConvertWithoutDowncast(meth->getArgByIndex(startarg,false)->fullName(),data)
				&& putType->canConvertWithoutDowncast(meth->getArgByIndex(startarg+1,false)->fullName(),data))
				return meth;
		}
	}
	return NULL;
}

Method * ClassSemantic::getBinaryOperator(const std::string & name, ClassSemantic * param,SemanticVisitorData * data)
{
  for (unsigned int i=0;i<m_operators.size();i++)
	{
		if (m_operators[i].m_operatorname==name)
		{
			Method * meth=getMethodByName(m_operators[i].m_methodname);
			int startarg=0;
			if (meth->findFormalArg("CURRENT")==0)
				startarg=1;
			//If fully exposed, use it
			if (meth->getArgByIndex(startarg,false)->fullName()==param->cnode()->name())
				return meth;
		}
	}
	
	for (unsigned int i=0;i<m_operators.size();i++)
	{
		if (m_operators[i].m_operatorname==name)
		{
			Method * meth=getMethodByName(m_operators[i].m_methodname);
			int startarg=0;
			if (meth->findFormalArg("CURRENT")==0)
				startarg=1;
			//If fully exposed, use it
			if (param->canConvertWithoutDowncast(meth->getArgByIndex(startarg,false)->fullName(),data))
				return meth;
		}
	}
	return NULL;
}

Method * ClassSemantic::getUnaryOperator(const std::string & name)
{
 for (unsigned int i=0;i<m_operators.size();i++)
 {
  if (m_operators[i].m_operatorname==name)
  {
	Method * meth=getMethodByName(m_operators[i].m_methodname);
	return meth;
  }
 }
 return NULL;
}


void ClassSemantic::addAnyIfNeed(SemanticVisitorData * data)
{
	bool canAdd=true;
	for (std::map<std::string,InheritanceSemantic>::iterator it=m_inheritance.begin();
		it!=m_inheritance.end();it++)
	{
		ClassSemantic * sem=data->getClassByName(it->first);
		if (sem)
			canAdd= canAdd && sem->isInterface();
	}
	if (this->isInterface()==false && canAdd && m_inheritance.find("ANY")==m_inheritance.end())
	{
	 m_inheritance.insert(std::make_pair<std::string,InheritanceSemantic>("ANY",InheritanceSemantic()));
	}	
}


ConstantTable * ParentData::currentTable()
{
	return this->CurrentClass->constantTable();
}

JBFile * ParentData::currentFile()
{
	return this->CurrentClass->file();
}
unsigned short ClassSemantic::getCompiledMethodsCount()
{
	unsigned short i=0;
	if (isRoot())
		i+=1;  // A main() function
	if (!isInterface())
		i+=1;  // A constructor
	for (std::map<std::string,Method>::iterator it=m_methods.begin();it!=m_methods.end();it++)
	{
		if (it->second.m_classname==cnode()->name() || it->second.shouldCompile())
		{
			unsigned int cur=1;
			if (it->second.shouldCompileMainMethod()==false)
				cur=0;
			i+=cur+it->second.m_overriden_methods.size();
		}
	}
	return i;
}

unsigned short ClassSemantic::getCompiledFieldsCount()
{
	unsigned short i=0;
	for (std::map<std::string,Field>::iterator it=m_fields.begin();it!=m_fields.end();it++)
	{
		if (it->second.m_classname==cnode()->name())
			++i;
	}
	return i;
}


void addUnique(std::vector<std::string> & v, const std::string &s )
{
	bool found=false;
	for (unsigned int i=0;i<v.size();i++)
		if (v[i]==s)
			found=true;
	if (!found)
		v.push_back(s);

}
std::vector<std::string> ClassSemantic::getAncestorsIncludingSelf(SemanticVisitorData * data)
{
	std::vector<std::string> result;
	result.push_back(cnode()->name());
	for (std::map<std::string,InheritanceSemantic>::iterator it=m_inheritance.begin();
		it!=m_inheritance.end();
		it++)
	{
		ClassSemantic * sem=data->getClassByName(it->first);
		if (sem) 
		{
		  std::vector<std::string> ancestors=sem->getAncestorsIncludingSelf(data);
		  for (unsigned int i=0;i<ancestors.size();i++)
			  addUnique(result,ancestors[i]);
		}
	}
	return result;
}
void ClassSemantic::checkDuplicateInheritance(SemanticVisitorData * data)
{
	std::vector< std::vector<std::string> > ancestors;
	for (std::map<std::string,InheritanceSemantic>::iterator it=m_inheritance.begin();
		it!=m_inheritance.end();it++)
	{
		ClassSemantic * sem=data->getClassByName(it->first);
		if (sem)
		{
			ancestors.push_back(sem->getAncestorsIncludingSelf(data));
		}
	}
	for (unsigned int i=0;i<ancestors.size();i++)
	{
		for (unsigned int curancestor=0;curancestor<ancestors[i].size();curancestor++)
		{
		 //Scan in other vectors for copies of ancestors[i][curancestor]
		 for (unsigned int j=i+1;j<ancestors.size();j++)
		 {
			 for (unsigned int possiblecopy=0;possiblecopy<ancestors[j].size();possiblecopy++)
			 {
				 if (ancestors[i][curancestor]==ancestors[j][possiblecopy])
				 {
					 data->add( new DuplicateInheritance(cnode(),cnode()->name(),ancestors[i][curancestor]));
				 }
			 }
		 }
		}
	}
}
